<template>
  <div class="kline-chart">
    <div class="chart-header">
      <div class="time-range">
        <el-radio-group v-model="timeRange" @change="handleTimeRangeChange">
          <el-radio-button label="day">日K</el-radio-button>
          <el-radio-button label="week">周K</el-radio-button>
          <el-radio-button label="month">月K</el-radio-button>
          <el-radio-button label="minute">分时</el-radio-button>
        </el-radio-group>
      </div>
      <div class="chart-tools">
        <el-button-group>
          <el-button size="small" @click="handleDrawLine('line')">直线</el-button>
          <el-button size="small" @click="handleDrawLine('horizontal')">水平线</el-button>
          <el-button size="small" @click="handleDrawLine('vertical')">垂直线</el-button>
          <el-button size="small" @click="handleDrawLine('parallel')">平行线</el-button>
          <el-button size="small" @click="handleDrawLine('fibonacci')">黄金分割</el-button>
        </el-button-group>
        <el-button size="small" @click="handleSaveLines">保存画线</el-button>
        <el-button size="small" @click="handleLoadLines">加载画线</el-button>
        <el-button size="small" @click="handleScreenshot">截图</el-button>
        <el-button size="small" @click="handleThemeChange">
          {{ isDarkTheme ? '浅色主题' : '深色主题' }}
        </el-button>
        <el-button size="small" @click="handleExportData">导出数据</el-button>
      </div>
      <div class="indicators">
        <el-select v-model="selectedIndicators" multiple placeholder="技术指标" @change="handleIndicatorChange">
          <el-option label="MA" value="MA"></el-option>
          <el-option label="MACD" value="MACD"></el-option>
          <el-option label="KDJ" value="KDJ"></el-option>
          <el-option label="RSI" value="RSI"></el-option>
          <el-option label="BOLL" value="BOLL"></el-option>
        </el-select>
      </div>
    </div>
    <div class="chart-container" ref="chartContainer"></div>
  </div>
</template>

<script>
import * as echarts from 'echarts'
import 'echarts/extension/bmap/bmap'
import { saveAs } from 'file-saver'

export default {
  name: 'KLineChart',
  props: {
    stockCode: {
      type: String,
      required: true
    },
    stockName: {
      type: String,
      required: true
    }
  },
  data() {
    return {
      chart: null,
      timeRange: 'day',
      selectedIndicators: ['MA', 'MACD'],
      klineData: [],
      volumeData: [],
      upColor: '#f56c6c',
      downColor: '#67c23a',
      upBorderColor: '#f56c6c',
      downBorderColor: '#67c23a',
      drawingMode: null,
      drawingLines: [],
      isDarkTheme: false,
      theme: {
        light: {
          backgroundColor: '#ffffff',
          textColor: '#333333',
          gridColor: '#f0f0f0',
          splitLineColor: '#f0f0f0'
        },
        dark: {
          backgroundColor: '#1f1f1f',
          textColor: '#ffffff',
          gridColor: '#2f2f2f',
          splitLineColor: '#2f2f2f'
        }
      }
    }
  },
  mounted() {
    this.initChart()
    this.fetchKLineData()
  },
  beforeDestroy() {
    if (this.chart) {
      this.chart.dispose()
    }
  },
  methods: {
    initChart() {
      this.chart = echarts.init(this.$refs.chartContainer)
      this.updateChart()
      
      // 添加画线事件监听
      this.chart.on('mousedown', this.handleMouseDown)
      this.chart.on('mousemove', this.handleMouseMove)
      this.chart.on('mouseup', this.handleMouseUp)
    },
    handleThemeChange() {
      this.isDarkTheme = !this.isDarkTheme
      this.updateChart()
    },
    handleScreenshot() {
      const dataURL = this.chart.getDataURL({
        type: 'png',
        pixelRatio: 2,
        backgroundColor: this.isDarkTheme ? '#1f1f1f' : '#ffffff'
      })
      const link = document.createElement('a')
      link.download = `${this.stockName}(${this.stockCode})_${this.timeRange}K.png`
      link.href = dataURL
      link.click()
    },
    handleSaveLines() {
      const lines = JSON.stringify(this.drawingLines)
      localStorage.setItem(`drawingLines_${this.stockCode}`, lines)
      this.$message.success('画线已保存')
    },
    handleLoadLines() {
      const lines = localStorage.getItem(`drawingLines_${this.stockCode}`)
      if (lines) {
        this.drawingLines = JSON.parse(lines)
        this.updateDrawingLines()
        this.$message.success('画线已加载')
      } else {
        this.$message.warning('没有找到保存的画线')
      }
    },
    handleDrawLine(type) {
      this.drawingMode = type
    },
    handleMouseDown(params) {
      if (!this.drawingMode) return
      
      const point = [params.offsetX, params.offsetY]
      this.drawingLines.push({
        type: this.drawingMode,
        points: [point],
        isDrawing: true
      })
    },
    handleMouseMove(params) {
      if (!this.drawingMode || !this.drawingLines.length) return
      
      const currentLine = this.drawingLines[this.drawingLines.length - 1]
      if (!currentLine.isDrawing) return
      
      const point = [params.offsetX, params.offsetY]
      currentLine.points[1] = point
      this.updateDrawingLines()
    },
    handleMouseUp() {
      if (!this.drawingMode || !this.drawingLines.length) return
      
      const currentLine = this.drawingLines[this.drawingLines.length - 1]
      currentLine.isDrawing = false
      this.drawingMode = null
    },
    updateDrawingLines() {
      const option = this.chart.getOption()
      const graphic = this.drawingLines.map(line => {
        const points = line.points
        if (points.length < 2) return null
        
        return {
          type: 'line',
          shape: {
            x1: points[0][0],
            y1: points[0][1],
            x2: points[1][0],
            y2: points[1][1]
          },
          style: {
            stroke: '#000',
            lineWidth: 1
          }
        }
      }).filter(Boolean)
      
      option.graphic = graphic
      this.chart.setOption(option)
    },
    handleExportData() {
      const data = this.klineData.map(item => ({
        日期: item.date,
        开盘价: item.open,
        收盘价: item.close,
        最高价: item.high,
        最低价: item.low,
        成交量: item.volume
      }))
      
      const csv = this.convertToCSV(data)
      const blob = new Blob([csv], { type: 'text/csv;charset=utf-8' })
      saveAs(blob, `${this.stockName}(${this.stockCode})_${this.timeRange}K数据.csv`)
    },
    convertToCSV(data) {
      const headers = Object.keys(data[0])
      const rows = data.map(item => headers.map(header => item[header]))
      return [headers, ...rows].map(row => row.join(',')).join('\n')
    },
    updateChart() {
      const currentTheme = this.isDarkTheme ? this.theme.dark : this.theme.light
      
      const option = {
        backgroundColor: currentTheme.backgroundColor,
        title: {
          text: `${this.stockName}(${this.stockCode})`,
          left: 0,
          textStyle: {
            fontSize: 16,
            fontWeight: 'bold',
            color: currentTheme.textColor
          }
        },
        tooltip: {
          trigger: 'axis',
          axisPointer: {
            type: 'cross',
            label: {
              backgroundColor: '#6a7985'
            }
          },
          formatter: (params) => {
            const date = params[0].axisValue
            const kline = params.find(p => p.seriesName === '日K')
            const result = [`日期：${date}`]
            
            if (kline) {
              result.push(`开盘：${kline.data[0]}`)
              result.push(`收盘：${kline.data[1]}`)
              result.push(`最低：${kline.data[2]}`)
              result.push(`最高：${kline.data[3]}`)
            }

            params.forEach(param => {
              if (param.seriesName !== '日K') {
                result.push(`${param.seriesName}：${param.data}`)
              }
            })

            return result.join('<br/>')
          }
        },
        legend: {
          data: ['日K', 'MA5', 'MA10', 'MA20', 'MA30', 'MACD', 'DIF', 'DEA', 'KDJ', 'K', 'D', 'J', 'RSI', 'BOLL', 'UPPER', 'LOWER'],
          selected: {
            '日K': true,
            'MA5': true,
            'MA10': true,
            'MA20': true,
            'MA30': true,
            'MACD': true,
            'DIF': true,
            'DEA': true,
            'KDJ': false,
            'K': false,
            'D': false,
            'J': false,
            'RSI': false,
            'BOLL': false,
            'UPPER': false,
            'LOWER': false
          },
          textStyle: {
            color: currentTheme.textColor
          }
        },
        grid: [
          {
            left: '3%',
            right: '1%',
            height: '60%',
            borderColor: currentTheme.gridColor
          },
          {
            left: '3%',
            right: '1%',
            top: '75%',
            height: '20%',
            borderColor: currentTheme.gridColor
          }
        ],
        xAxis: [
          {
            type: 'category',
            data: this.klineData.map(item => item.date),
            scale: true,
            boundaryGap: false,
            axisLine: { onZero: false },
            splitLine: { show: false },
            min: 'dataMin',
            max: 'dataMax',
            axisLabel: {
              formatter: (value) => {
                return value.split('-').slice(1).join('-')
              },
              color: currentTheme.textColor
            }
          },
          {
            type: 'category',
            gridIndex: 1,
            data: this.klineData.map(item => item.date),
            scale: true,
            boundaryGap: false,
            axisLine: { onZero: false },
            axisTick: { show: false },
            splitLine: { show: false },
            axisLabel: { show: false },
            min: 'dataMin',
            max: 'dataMax'
          }
        ],
        yAxis: [
          {
            scale: true,
            splitArea: {
              show: true,
              areaStyle: {
                color: [currentTheme.gridColor, currentTheme.splitLineColor]
              }
            },
            axisLabel: {
              formatter: (value) => {
                return value.toFixed(2)
              },
              color: currentTheme.textColor
            }
          },
          {
            scale: true,
            gridIndex: 1,
            splitNumber: 2,
            axisLabel: { show: false },
            axisLine: { show: false },
            axisTick: { show: false },
            splitLine: { show: false }
          }
        ],
        dataZoom: [
          {
            type: 'inside',
            xAxisIndex: [0, 1],
            start: 0,
            end: 100,
            zoomLock: false
          },
          {
            show: true,
            xAxisIndex: [0, 1],
            type: 'slider',
            bottom: '1%',
            height: 20,
            borderColor: 'transparent',
            backgroundColor: currentTheme.gridColor,
            fillerColor: 'rgba(0,0,0,0.1)',
            handleStyle: {
              color: '#d7d7d7',
              borderColor: '#b7b7b7'
            },
            moveHandleStyle: {
              color: '#b7b7b7'
            }
          }
        ],
        series: [
          {
            name: '日K',
            type: 'candlestick',
            data: this.klineData.map(item => [
              item.open,
              item.close,
              item.low,
              item.high
            ]),
            itemStyle: {
              color: this.upColor,
              color0: this.downColor,
              borderColor: this.upBorderColor,
              borderColor0: this.downBorderColor
            }
          },
          {
            name: '成交量',
            type: 'bar',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: this.volumeData,
            itemStyle: {
              color: (params) => {
                const data = this.klineData[params.dataIndex]
                return data.close >= data.open ? this.upColor : this.downColor
              }
            }
          }
        ]
      }

      // 添加选中的技术指标
      if (this.selectedIndicators.includes('MA')) {
        option.series.push(
          {
            name: 'MA5',
            type: 'line',
            data: this.calculateMA(5),
            smooth: true,
            lineStyle: {
              width: 1,
              opacity: 0.8
            }
          },
          {
            name: 'MA10',
            type: 'line',
            data: this.calculateMA(10),
            smooth: true,
            lineStyle: {
              width: 1,
              opacity: 0.8
            }
          },
          {
            name: 'MA20',
            type: 'line',
            data: this.calculateMA(20),
            smooth: true,
            lineStyle: {
              width: 1,
              opacity: 0.8
            }
          },
          {
            name: 'MA30',
            type: 'line',
            data: this.calculateMA(30),
            smooth: true,
            lineStyle: {
              width: 1,
              opacity: 0.8
            }
          }
        )
      }

      if (this.selectedIndicators.includes('MACD')) {
        const macd = this.calculateMACD()
        const dif = this.calculateDIF()
        const dea = this.calculateDEA()
        
        option.series.push(
          {
            name: 'MACD',
            type: 'bar',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: macd,
            itemStyle: {
              color: (params) => {
                return params.data >= 0 ? this.upColor : this.downColor
              }
            }
          },
          {
            name: 'DIF',
            type: 'line',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: dif,
            lineStyle: {
              width: 1
            }
          },
          {
            name: 'DEA',
            type: 'line',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: dea,
            lineStyle: {
              width: 1
            }
          }
        )
      }

      if (this.selectedIndicators.includes('KDJ')) {
        const kdj = this.calculateKDJ()
        option.series.push(
          {
            name: 'K',
            type: 'line',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: kdj.map(item => item.k),
            lineStyle: {
              width: 1
            }
          },
          {
            name: 'D',
            type: 'line',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: kdj.map(item => item.d),
            lineStyle: {
              width: 1
            }
          },
          {
            name: 'J',
            type: 'line',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: kdj.map(item => item.j),
            lineStyle: {
              width: 1
            }
          }
        )
      }

      if (this.selectedIndicators.includes('RSI')) {
        const rsi = this.calculateRSI()
        option.series.push(
          {
            name: 'RSI',
            type: 'line',
            xAxisIndex: 1,
            yAxisIndex: 1,
            data: rsi,
            lineStyle: {
              width: 1
            }
          }
        )
      }

      if (this.selectedIndicators.includes('BOLL')) {
        const boll = this.calculateBOLL()
        option.series.push(
          {
            name: 'BOLL',
            type: 'line',
            data: boll.map(item => item.mid),
            lineStyle: {
              width: 1
            }
          },
          {
            name: 'UPPER',
            type: 'line',
            data: boll.map(item => item.upper),
            lineStyle: {
              width: 1,
              type: 'dashed'
            }
          },
          {
            name: 'LOWER',
            type: 'line',
            data: boll.map(item => item.lower),
            lineStyle: {
              width: 1,
              type: 'dashed'
            }
          }
        )
      }

      this.chart.setOption(option)
    },
    calculateMA(dayCount) {
      const result = []
      for (let i = 0; i < this.klineData.length; i++) {
        if (i < dayCount - 1) {
          result.push('-')
          continue
        }
        let sum = 0
        for (let j = 0; j < dayCount; j++) {
          sum += this.klineData[i - j].close
        }
        result.push((sum / dayCount).toFixed(2))
      }
      return result
    },
    calculateMACD() {
      const dif = this.calculateDIF()
      const dea = this.calculateDEA()
      const macd = dif.map((item, index) => {
        return ((item - dea[index]) * 2).toFixed(2)
      })
      return macd
    },
    calculateDIF() {
      const ema12 = this.calculateEMA(12)
      const ema26 = this.calculateEMA(26)
      return ema12.map((item, index) => {
        return (item - ema26[index]).toFixed(2)
      })
    },
    calculateDEA() {
      const dif = this.calculateDIF()
      return this.calculateEMA(9, dif)
    },
    calculateEMA(period, data = this.klineData.map(item => item.close)) {
      const result = []
      const multiplier = 2 / (period + 1)
      
      for (let i = 0; i < data.length; i++) {
        if (i === 0) {
          result.push(data[i])
        } else {
          result.push((data[i] * multiplier + result[i - 1] * (1 - multiplier)).toFixed(2))
        }
      }
      return result
    },
    calculateKDJ() {
      const kdj = []
      const rsv = []
      
      for (let i = 0; i < this.klineData.length; i++) {
        const high = Math.max(...this.klineData.slice(Math.max(0, i - 8), i + 1).map(item => item.high))
        const low = Math.min(...this.klineData.slice(Math.max(0, i - 8), i + 1).map(item => item.low))
        const close = this.klineData[i].close
        
        if (high === low) {
          rsv.push(50)
        } else {
          rsv.push(((close - low) / (high - low) * 100).toFixed(2))
        }
      }
      
      let k = 50
      let d = 50
      
      for (let i = 0; i < rsv.length; i++) {
        k = (2/3) * k + (1/3) * rsv[i]
        d = (2/3) * d + (1/3) * k
        const j = 3 * k - 2 * d
        
        kdj.push({
          k: k.toFixed(2),
          d: d.toFixed(2),
          j: j.toFixed(2)
        })
      }
      
      return kdj
    },
    calculateRSI(period = 14) {
      const rsi = []
      const changes = []
      
      for (let i = 1; i < this.klineData.length; i++) {
        changes.push(this.klineData[i].close - this.klineData[i - 1].close)
      }
      
      for (let i = 0; i < this.klineData.length; i++) {
        if (i < period) {
          rsi.push('-')
          continue
        }
        
        const gains = changes.slice(i - period, i).filter(change => change > 0)
        const losses = changes.slice(i - period, i).filter(change => change < 0)
        
        const avgGain = gains.reduce((sum, gain) => sum + gain, 0) / period
        const avgLoss = Math.abs(losses.reduce((sum, loss) => sum + loss, 0)) / period
        
        if (avgLoss === 0) {
          rsi.push(100)
        } else {
          const rs = avgGain / avgLoss
          rsi.push((100 - (100 / (1 + rs))).toFixed(2))
        }
      }
      
      return rsi
    },
    calculateBOLL() {
      const boll = []
      const period = 20
      
      for (let i = 0; i < this.klineData.length; i++) {
        if (i < period - 1) {
          boll.push({ mid: '-', upper: '-', lower: '-' })
          continue
        }
        
        const closes = this.klineData.slice(i - period + 1, i + 1).map(item => item.close)
        const mid = closes.reduce((sum, close) => sum + close, 0) / period
        const std = Math.sqrt(closes.reduce((sum, close) => sum + Math.pow(close - mid, 2), 0) / period)
        
        boll.push({
          mid: mid.toFixed(2),
          upper: (mid + 2 * std).toFixed(2),
          lower: (mid - 2 * std).toFixed(2)
        })
      }
      
      return boll
    },
    handleTimeRangeChange() {
      this.fetchKLineData()
    },
    handleIndicatorChange() {
      this.updateChart()
    },
    async fetchKLineData() {
      // TODO: 调用后端接口获取K线数据
      // 这里使用模拟数据
      if (this.timeRange === 'minute') {
        // 分时图数据
        this.klineData = Array.from({ length: 240 }, (_, i) => {
          const basePrice = 100
          const time = `${Math.floor(i / 60) + 9}:${(i % 60).toString().padStart(2, '0')}`
          const price = basePrice + Math.sin(i / 10) * 2
          return {
            date: time,
            open: price,
            close: price,
            low: price - 0.5,
            high: price + 0.5,
            volume: Math.floor(Math.random() * 10000) + 5000
          }
        })
      } else {
        // K线图数据
        this.klineData = [
          { date: '2024-01-01', open: 100, close: 102, low: 98, high: 105, volume: 10000 },
          { date: '2024-01-02', open: 102, close: 105, low: 101, high: 108, volume: 12000 },
          { date: '2024-01-03', open: 105, close: 103, low: 100, high: 106, volume: 8000 },
          { date: '2024-01-04', open: 103, close: 108, low: 102, high: 110, volume: 15000 },
          { date: '2024-01-05', open: 108, close: 106, low: 104, high: 109, volume: 9000 }
        ]
      }
      this.volumeData = this.klineData.map(item => item.volume)
      this.updateChart()
    }
  }
}
</script>

<style scoped>
.kline-chart {
  width: 100%;
  height: 100%;
  padding: 16px;
  box-sizing: border-box;
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 16px;
  padding: 12px;
  background-color: var(--el-bg-color);
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

.time-range {
  display: flex;
  align-items: center;
}

.chart-tools {
  display: flex;
  align-items: center;
  gap: 8px;
}

.indicators {
  display: flex;
  align-items: center;
}

.chart-container {
  width: 100%;
  height: 500px;
  background-color: var(--el-bg-color);
  border-radius: 4px;
  box-shadow: 0 2px 12px 0 rgba(0, 0, 0, 0.1);
}

:deep(.el-radio-group) {
  display: flex;
  gap: 4px;
}

:deep(.el-radio-button__inner) {
  padding: 8px 16px;
}

:deep(.el-button-group) {
  display: flex;
  gap: 4px;
}

:deep(.el-button) {
  padding: 8px 16px;
}

:deep(.el-select) {
  width: 180px;
}

:deep(.el-select .el-input__inner) {
  padding: 8px 16px;
}
</style> 